import java.util.Collection;
import java.util.Enumeration;
import java.util.concurrent.ConcurrentHashMap;

//Tabs = 4
//************************************************************
//	COPYRIGHT 2011 Bread Zeppelin - ALL RIGHTS RESERVED
//
//This file is the product of Bread Zeppelin and cannot be 
//reproduced, copied, or used in any shape or form without 
//the express written consent of Bread Zeppelin.
//************************************************************
//
//	$ID: Concurrent_Assg6
//
//	$Date: Feb 13, 2012
//
//	Reason:
//
//*************************************************************

/** $Author: Ben Hare, Zach Huenink, Philipp Wittmaack, Peter Maresca */
/** $Revision: 1 */

//Default Package

public class RestaurantMetrics {
	private ConcurrentHashMap<Object,Number> seatTime; //AcceptCustomer_Task
	private ConcurrentHashMap<Object,Number> waitTime; //SeatCustomer_Task
	private ConcurrentHashMap<Object,Number> hostessIdleTime; //Hostess Executor
	private ConcurrentHashMap<Object,Number> waitressIdleTime; //Waitress Executor
	private ConcurrentHashMap<Object,Number> cookIdleTime; //Cook Executor
	private ConcurrentHashMap<Object,Number> runnerIdleTime; //Food Runner Executor
	private ConcurrentHashMap<Object,Number> cookTime; //Cook time of an order: Order Object
	private ConcurrentHashMap<Object,Number> customerTime; //Average time customer spends in restaurant
	private ConcurrentHashMap<Object,Number> waitingToOrderTime; //Time customer waits to order.
	private ConcurrentHashMap<Object,Number> fromOrderToDeliveryTime; //Time customer waits from ordering to receiving food.

	public static RestaurantMetrics metrics = null;

	private RestaurantMetrics(){
		seatTime = new ConcurrentHashMap<Object,Number>();
		waitTime = new ConcurrentHashMap<Object,Number>();
		hostessIdleTime = new ConcurrentHashMap<Object,Number>();
		waitressIdleTime = new ConcurrentHashMap<Object,Number>();
		cookIdleTime = new ConcurrentHashMap<Object,Number>();
		runnerIdleTime = new ConcurrentHashMap<Object,Number>();
		cookTime = new ConcurrentHashMap<Object,Number>();
		customerTime = new ConcurrentHashMap<Object,Number>();
		waitingToOrderTime = new ConcurrentHashMap<Object,Number>();
		fromOrderToDeliveryTime = new ConcurrentHashMap<Object,Number>();
	}

	public static RestaurantMetrics getInstance(){
		if (metrics == null){
			metrics = new RestaurantMetrics();
		}
		return metrics;
	}

	public void beginSeatTime(Object o, long time){
		seatTime.put(o, time);
	}
	public void finishSeatTime(Object o, long time){
		
		Number oldTime = seatTime.get(o);
		if (oldTime != null) {
			
			long total = time - oldTime.longValue();
			seatTime.put(o, total);
			
		}
		
	}

	public void beginWaitTime(Object o, long time){
		waitTime.put(o, time);
	}
	public void finishWaitTime(Object o, long time){
		
		Number oldTime = waitTime.get(o);
		if (oldTime != null) {
			
			long total = time - oldTime.longValue();
			waitTime.put(o, total);
			
		}
		
	}

	public void finishHostessTime(Object o, long time){
		hostessIdleTime.put(o, time);
	}

	public void finishWaitressTime(Object o, long time){
		waitressIdleTime.put(o, time);
	}

	public void finishCookTime(Object o, long time){
		cookIdleTime.put(o, time);
	}

	public void finishFoodRunnerTime(Object o, long time){
		runnerIdleTime.put(o, time);
	}

	public void beginCookOrderTime(Object o, long time){
		cookTime.put(o, time);
	}
	public void finishCookOrderTime(Object o, long time){
		long total = time - cookTime.get(o).longValue();
		cookTime.put(o, total);
	}

	public void beginCustomerTime(Object o, long time){
		customerTime.put(o, time);
	}
	public void finishCustomerTime(Object o, long time){

		Number oldTime = customerTime.get(o);
		if (oldTime != null) {
			
			long total = time - oldTime.longValue();
			customerTime.put(o, total);
			
		}
		
	}

	public void beginWaitingToOrderTime(Object o, long time){
		waitingToOrderTime.put(o, time);
	}
	public void finishWaitingToOrderTime(Object o, long time){
		
		Number oldTime = waitingToOrderTime.get(o);
		if (oldTime != null) {
			
			long total = time - oldTime.longValue();
			waitingToOrderTime.put(o, total);
			
		}
		
	}

	public void beginFromOrderToDeliveryTime(Object o, long time){
		fromOrderToDeliveryTime.put(o, time);
	}
	public void finishFromOrderToDeliveryTime(Object o, long time){
		
		Number oldTime = fromOrderToDeliveryTime.get(o);
		if (oldTime != null) {
			
			long total = time - oldTime.longValue();
			fromOrderToDeliveryTime.put(o, total);
			
		}
		
	}

	public synchronized void removeDataMetric(Object o) {
		seatTime.remove(o);
		waitTime.remove(o);
		cookTime.remove(o);
		customerTime.remove(o);
		waitingToOrderTime.remove(o);
		fromOrderToDeliveryTime.remove(o);
	}

	public String genericAverage( ConcurrentHashMap<Object,Number> hash) {

		Collection<Number> values = hash.values();
		long size = values.size();
		long total = 0;

		for (Enumeration<Number> e = hash.elements(); e.hasMoreElements(); ) {
			total = total + e.nextElement().longValue();
		} 

		if (size == 0) {
			return "0";
		}
		return "" + ((total/size)/1000)* Simulator.simulationSpeed;

	}

	//-------------------
	public String print_seatTimeAverage(){
		return genericAverage(seatTime);
	}

	public String print_waitTimeAverage(){
		return genericAverage(waitTime);
	}

	public String print_hostessIdleAverage(){
		return genericAverage(hostessIdleTime);
	}

	public String print_waitressIdleAverage(){
		return genericAverage(waitressIdleTime);
	}

	public String print_cookIdleAverage(){
		return genericAverage(cookIdleTime);
	}

	public String print_foodRunnerAverage(){
		return genericAverage(runnerIdleTime);
	}

	public String print_cookTimeAverage(){
		return genericAverage(cookTime);
	}

	public String print_customerTimeAverage(){
		return genericAverage(customerTime);
	}

	public String print_waitingToOrderAverage(){
		return genericAverage(waitingToOrderTime);
	}

	public String print_fromOrderToDeliveryAverage(){
		return genericAverage(fromOrderToDeliveryTime);
	}

}
